「一句喊出口的指控會隨風散去;一份寫下來、分好段落的指控,才經得起明天全村逐字翻查。」
——《阿帕契開源審計錄》¹ 卷三·提案篇
幕間
敘事者在心中盤算決戰:「神職只剩女巫了。只要我白天自爆控刀,二號夜裡刀掉女巫,狼人屠邊獲勝!」
他對這條必勝路徑深信不疑:前幾世,六號也這樣自稱獵人,他從沒親眼看過這個人開槍。他完全沒發覺自己正依循一張被神明竄改過的地圖邁向毀滅,更沒想到那個座位上,只是一個演得太好的好人。
宣讀前的那一夜,七號沒有站起來指著二號大喊「他是狼」。她把羊皮紙攤在膝上,用炭筆在頁面上畫了四條橫線,分成四個帶標題的區塊,然後一格一格往裡填。隔壁的平民探頭問她:明天開口講不就好了,寫這些做什麼?她頭也沒抬:「講出來的話,這一輪結束就沒人記得細節了;寫下來的東西,明天他們可以一行一行挑我毛病。我要的就是這個。」
長桌對面,二號的手指在桌沿下方輕輕比劃,像是在跟著某個節奏記數。有人問他在做什麼,他說「隨手比劃」,然後把手收了回去。他從來沒有讓任何人看過他到底記了什麼。
那一夜法官罕見地離了一會兒席。他起身走動時,我第一次看清:面具底下是有輪廓的,長袍裡是有重量的——他不是一道憑空的聲音,是一個人。是人,也許就有能被攔下、被說動的一天。這個念頭讓我心跳漏了一拍,我沒敢往下想。
一份要被全村挑剔的指控,為什麼值得先花一夜寫成文件?因為開源世界裡最重要的溝通,本來就長這個樣子。
新手以為一個 Pull Request 就是一段 diff:程式碼貼上去,等人按合併。做過幾年的人知道,diff 是最不花力氣的部分,真正的工作是那段說明。維護者一天可能收到幾十個 PR,他憑什麼先看你的?憑你有沒有把四件事講清楚:Context(背景)、Problem(痛點)、Solution(設計取捨)、Verification(測試證明)。多數被晾在一旁沒人理的 PR,不是程式碼爛,而是作者只丟了程式碼、什麼都沒解釋,等於要審查者替他把上下文重建一遍。
維護者的時間是專案裡最稀缺的資源。一份好的 PR 說明,等於幫他把「這個改動要不要收」這個決策的前置作業做完:他不需要去翻你引用的那張 issue、不需要 checkout 你的分支才知道你在解什麼、不需要猜你為什麼選 A 不選 B。你替他省下的每一分鐘,都會回報在合併速度上。反過來,一份逼審查者當考古學家的 PR,通常的下場就是被標記「等作者補充」,然後石沉大海。這四段不是官僚表格,是把你腦中的決策過程外部化,讓別人能接手判斷。
## Context
- Subsystem, version, config flags in play. Link the issue.
- What a reviewer must know to evaluate this change at all.
## Problem
- One concrete failure: reproduction steps or a failing test.
- Why it matters now, and who is affected.
## Solution
- The design chosen, in two or three sentences.
- Alternatives rejected, and the trade-off accepted.
- Blast radius: what this change explicitly does NOT touch.
## Verification
- New tests and what they assert.
- How to reproduce the green result locally.
- Benchmarks or logs if behaviour or performance shifted.
壞的 Context 常常只是把標題再講一次:標題寫「修好登入逾時」,Context 就寫「這個 PR 修好了登入逾時的問題」——等於沒寫。有資訊量的 Context 會補上標題塞不下的東西:哪個模組、從哪個版本開始出現、觸發條件是什麼、可以用哪個指令重現、關聯的 issue 是哪一張。判準很簡單:一個從沒碰過這塊程式碼的人讀完,能不能大致知道你站在哪裡。
四段裡最容易寫壞的是 Problem 和 Solution,因為作者太清楚答案,會把問題寫成結論。
Problem 要能脫離你的解法單獨成立。 審查者必須能在還沒看你怎麼修之前,就自己判斷「這確實是問題、值得現在處理」。如果 Problem 段寫成「因為 X 函式沒加鎖,所以我加了鎖」,他就沒有機會反對你的問題認定,只能連著解法一起吞。正確的寫法是先講現象:什麼輸入、什麼併發條件、觀察到什麼錯誤結果,讓他先點頭「對,這要修」,再往下看。
Solution 的價值在你捨棄的那些選項。 只說「我用了方案 A」等於什麼都沒說;說「我考慮過在呼叫端加檢查,但那會讓每個使用者都得記得做一次,所以改成在建構子強制」,審查者才知道你想過、也知道可以從哪裡挑戰你。被你寫下來否決掉的方案,幫他省下了「這人有沒有想到這個」的來回。
Verification 要指名道姓。 「測試通過」不是證明,因為舊測試本來就通過。可信的 Verification 會說:這個具體案例在改動前會失敗、改動後會通過。最好的形式就是一個新測試——它同時是 Problem 的重現和 Solution 的驗收:
func TestParseTimeline_RejectsBrokenInput(t *testing.T) {
// Before this PR: decode() swallowed the error and returned an empty
// Accusation, so a malformed line passed silently as "no evidence".
_, err := ParseTimeline("night=3;actor=") // actor value is missing
if err == nil {
t.Fatal("want a parse error for malformed input, got nil")
}
}
四段結構之外,還有兩個常被忽略的細節。第一是標題:它是這份 PR 的一行摘要,用祈使句寫「做了什麼」,而不是「我改了一些東西」——維護者在一長串列表裡靠標題決定點不點進來。第二是體積:一個 PR 只做一件邏輯上完整的事。
一個同時做兩件事的 PR,代價是實打實的。審查者得同時在腦中維護兩條 Context,注意力被稀釋,漏看的機率上升;Verification 寫不乾淨,因為兩件事的驗收糾纏在一起;真的出事要回滾時,你被迫連好的那半也一起退掉;日後有人用 git bisect 追一個 regression,定位到這個 commit 卻分不清是哪一半造成的。順手改的排版、擦到的 typo、想到就加的小功能,全部拆成獨立的 PR。七號的指控之所以有效,正因為她只指控一件事——二號的固定模式——而不是把二號三十天所有可疑的地方全倒出來。
一份好的 PR 說明,是照著審查者腦子裡的檢查順序寫的。他讀 Context 是為了重建你的世界;讀 Problem 是為了確認這個痛是真的、而且只有一個;讀 Solution 是為了檢查你的取捨站不站得住;讀 Verification 是為了自己動手重跑一次。任何一關過不了,他就按下 Request Changes,而且通常不會告訴你他卡在哪一段——所以四段都要先自己走過一遍。

四段結構寫得再工整,作者終究是當事人——自己最容易對自己的邏輯漏洞視而不見。這幾年開始普及的做法,是在 PR 送到人類審查者手上之前,先讓一個自動化的審查關卡跑過一輪。以 Claude Code 為例,它內建的程式碼審查能力可以針對一份 diff 或指定的 PR,在你設定的嚴謹程度下抓正確性錯誤與可簡化之處,並且能直接把發現的問題以行內留言的形式貼回 PR,或是在確認後直接把修正套用回工作樹——等於是把「審查者的心智模型」那張流程圖,提前跑了一遍空機。Anthropic 也把這個能力做成官方的 GitHub Actions 整合,讓它在 PR 一開啟時就自動介入,而不必每次手動觸發。
這不是要取代七號那份手寫的指控書,而是把它的第一輪挑剔外包出去:邏輯漏洞、明顯的正確性問題,讓機器先挑掉;真正值得維護者花時間的架構取捨與業務判斷,才留給人。
同一個夜裡,狼的那張桌子也在寫自己的提案,只是內容短得多。我先開口提了一個目標,二號沒有多問,點了一下頭。刀就這樣定了,誰也沒有留下一個字的紀錄。
七號寫完的時候天快亮了。第二天她不是用喊的,而是一段一段唸出來:先交代她從第幾夜開始記、記了哪些欄位(Context);再指出二號那條「從不第一個開口」的固定模式(Problem);接著說明她為什麼排除「他只是性格保守」這個解釋(Solution);最後攤開羊皮紙上那張逐夜對照表(Verification)。
全場第一次沒有跟她的語氣吵架,而是直接跳進她的對照表裡找漏洞——這反而代表他們終於把她的話當一回事了。一份寫得夠結構化的指控,換來的不是掌聲,是被人認真拆解的資格。你的 PR 也一樣:目標從來不是一次過關,而是讓討論能聚焦在真正的技術點上,而不是卡在「你到底想幹嘛」。至於被逐句挑剔會發生什麼事、要怎麼接住那些 -1,那是明天的功課。
讀完這篇,你現在該做的是:下一個 PR,先把 Context、Problem、Solution、Verification 四段寫完,再動手改程式碼;打開 Kubernetes 或 Kafka 的貢獻指南,照它的 checklist 對一遍自己的說明。Google 工程實踐的 Code Review 指南與 opensource.guide 都有完整的 PR 寫作教學可以照著練。
"perfect pull request description" "PR context problem solution verification" "open source code review checklist" "Kafka contributing guide PR" "Claude Code automated PR review"
¹ 註:本書名為情境設定之虛構文獻,非真實歷史或開源紀錄。